/****************************************Copyright (c)*************************
**                               版权所有 (C), 2020-2030, 零匙科技
**
**                                 https://www.0k.com/
**
**
**-----------------------------------------------------------------------------
**--------------当前版本修订---------------------------------------------------
** 版  本: v1.0.0
** 日　期: 2022年02月15日
** 描　述: 1:协议初版
** 作  者：zouchuan
**-----------------------------------------------------------------------------
******************************************************************************/

#include "hal_debug.h"
#include "leokey_ble.h"

/*****************************************************************************
函数名称 : hex_to_bcd
功能描述 : hex转bcd
输入参数 : Value_H:高字节/Value_L:低字节
返回参数 : bcd_value:转换完成后数据
*****************************************************************************/
unsigned char hex_to_bcd(unsigned char Value_H, unsigned char Value_L)
{
    unsigned char bcd_value;

    if ((Value_H >= '0') && (Value_H <= '9'))
        Value_H -= '0';
    else if ((Value_H >= 'A') && (Value_H <= 'F'))
        Value_H = Value_H - 'A' + 10;
    else if ((Value_H >= 'a') && (Value_H <= 'f'))
        Value_H = Value_H - 'a' + 10;

    bcd_value = Value_H & 0x0f;

    bcd_value <<= 4;
    if ((Value_L >= '0') && (Value_L <= '9'))
        Value_L -= '0';
    else if ((Value_L >= 'A') && (Value_L <= 'F'))
        Value_L = Value_L - 'a' + 10;
    else if ((Value_L >= 'a') && (Value_L <= 'f'))
        Value_L = Value_L - 'a' + 10;

    bcd_value |= Value_L & 0x0f;

    return bcd_value;
}

/*****************************************************************************
函数名称 : my_strlen
功能描述 : 求字符串长度
输入参数 : src:源地址
返回参数 : len:数据长度
*****************************************************************************/
unsigned long my_strlen(unsigned char *str)
{
    unsigned long len = 0;
    if (str == NULL)
    {
        return 0;
    }

    for (len = 0; *str++ != '\0';)
    {
        len++;
    }

    return len;
}

/*****************************************************************************
函数名称 : my_memset
功能描述 : 把src所指内存区域的前count个字节设置成字符c
输入参数 : src:源地址
           ch:设置字符
           count:设置数据长度
返回参数 : src:数据处理完后的源地址
*****************************************************************************/
void *my_memset(void *src, unsigned char ch, unsigned short count)
{
    unsigned char *tmp = (unsigned char *) src;
    if (src == NULL)
    {
        return NULL;
    }

    while (count--)
    {
        *tmp++ = ch;
    }
    return src;
}

/*****************************************************************************
函数名称 : mymemcpy
功能描述 : 内存拷贝
输入参数 : dest:目标地址
           src:源地址
           count:数据拷贝数量
返回参数 : src:数据处理完后的源地址
*****************************************************************************/
void *my_memcpy(void *dest, const void *src, unsigned short count)
{
    unsigned char *pdest = (unsigned char *) dest;
    const unsigned char *psrc = (const unsigned char *) src;
    unsigned short i;

    if (dest == NULL || src == NULL)
    {
        return NULL;
    }

    if ((pdest <= psrc) || (pdest > psrc + count))
    {
        for (i = 0; i < count; i++)
        {
            pdest[i] = psrc[i];
        }
    }
    else
    {
        for (i = count; i > 0; i--)
        {
            pdest[i - 1] = psrc[i - 1];
        }
    }

    return dest;
}

/*****************************************************************************
函数名称 : my_strcpy
功能描述 : 内存拷贝
输入参数 : s1:目标地址
           s2:源地址
返回参数 : 数据处理完后的源地址
*****************************************************************************/
char *my_strcpy(char *dest, const char *src)
{
    char *p = dest;
    while (*src != '\0')
    {
        *dest++ = *src++;
    }
    *dest = '\0';
    return p;
}

/*****************************************************************************
函数名称 : my_strcmp
功能描述 : 内存拷贝
输入参数 : s1:字符串1
           s2:字符串2
返回参数 : 大小比较值，0:s1=s2; -1:s1<s2; 1:s1>s2
*****************************************************************************/
int my_strcmp(char *s1, char *s2)
{
    while (*s1 && *s2 && *s1 == *s2)
    {
        s1++;
        s2++;
    }
    return *s1 - *s2;
}

/*****************************************************************************
函数名称 : byte_to_short
功能描述 : 将2字节合并为1个16bit变量
输入参数 : value:2字节数组
返回参数 : number:合并完成后的16bit变量
****************************************************************************/
unsigned short int byte_to_short(const unsigned char value[2])
{
    unsigned short int nubmer = 0;

    nubmer = (unsigned short int) value[0];
    nubmer <<= 8;
    nubmer |= (unsigned short int) value[1];

    return nubmer;
}

/*****************************************************************************
函数名称 : int_to_byte
功能描述 : 将int类型拆分四个字节
输入参数 : number:4字节原数据;value:处理完成后4字节数据
返回参数 :无
****************************************************************************/
void int_to_byte(unsigned long number, unsigned char value[4])
{
    value[0] = number >> 24;
    value[1] = number >> 16;
    value[2] = number >> 8;
    value[3] = number & 0xff;
}

/*****************************************************************************
函数名称 : byte_to_int
功能描述 : 将4字节合并为1个32bit变量
输入参数 : value:4字节数组
返回参数 : number:合并完成后的32bit变量
****************************************************************************/
unsigned long byte_to_int(const unsigned char value[4])
{
    unsigned long nubmer = 0;

    nubmer = (unsigned long) value[0];
    nubmer <<= 8;
    nubmer |= (unsigned long) value[1];
    nubmer <<= 8;
    nubmer |= (unsigned long) value[2];
    nubmer <<= 8;
    nubmer |= (unsigned long) value[3];

    return nubmer;
}


//============================================================================
//============================================================================


/*****************************************************************************
函数名称 : uart_receive_input
功能描述 : 收数据处理
输入参数 : value:串口收到字节数据
返回参数 : 无
使用说明 : 在MCU串口接收函数中调用该函数,并将接收到的数据作为参数传入
*****************************************************************************/
typedef enum
{
    SOP_STATE = 0x00,
    CMD_VERSION = 0x01,
    SEQ_STATE_H = 0x02,
    SEQ_STATE_L = 0x03,
    CMD_CMD = 0x04,
    LEN_STATE_H = 0x05,
    LEN_STATE_L = 0x06,
    DATA_STATE = 0x07,
    FCS_STATE = 0x08,
    MT_UART_SOF = 0xFE,
    SOP_INIT = 0XFF,
} teSL_RxState;


unsigned char uart_receive_input(unsigned char ch)
{

    //#error "5、请将MCU串口接收函数中添加该函数，并删除该行"

    static unsigned short pu16Length = 0;
    static unsigned short tempDataLen = 0;
    static unsigned char state = SOP_INIT;
    

    switch (state)
    {
        //确认第一个字节：帧头0x55
        case SOP_INIT:  
            if (ch == FRAME_FIRST)   
            {
                leokey_ble_queue_buf[HEAD_FIRST] = ch;
                state = SOP_STATE;
            }
            break;

        //确认第二个字节：帧头0xaa
        case SOP_STATE: 
            if (ch == FRAME_SECOND)    
            {
                leokey_ble_queue_buf[HEAD_SECOND] = ch;
                state = CMD_VERSION;
            }
            else
            {
                state = SOP_INIT;
            }
            break;

        //确认第三个字节：协议版本号0x01
        case CMD_VERSION: 
            if (ch == VERSION)    
            {
                leokey_ble_queue_buf[PROTOCOL_VERSION] = ch;
                state = SEQ_STATE_H;//CMD_TYPE;
            }
            else
            {
                state = SOP_INIT;
            }
            break;

        //业务序列号高字节
        case SEQ_STATE_H: 
            leokey_ble_queue_buf[SEQUENCEH] = ch;    
            state = SEQ_STATE_L;
            break;

        //业务序列号低字节
        case SEQ_STATE_L: 
            leokey_ble_queue_buf[SEQUENCEL] = ch;    
            state = CMD_CMD;
            break;

        //第五个字节：命令字
        case CMD_CMD: 
            leokey_ble_queue_buf[FRAME_CMD] = ch;    
            state = LEN_STATE_H;
            pu16Length = 0;
            break;

        //第六个字节：数据长度
        case LEN_STATE_H: 
            leokey_ble_queue_buf[LENGTH] = ch;    
            pu16Length = ch << 8;    //高字节
            state = LEN_STATE_L;
            break;

        //第七个字节：数据长度
        case LEN_STATE_L: 
            leokey_ble_queue_buf[LENGTL] = ch;    
            pu16Length |= ch;    //低字节长度
            tempDataLen = 0;    //记录数据长度
            if (!pu16Length)    //数据长度为0
            {
                state = FCS_STATE;
            }
            else
            {
                state = DATA_STATE;    //数据长度非0
            }
            break;

        //存储数据
        case DATA_STATE: 
            leokey_ble_queue_buf[DATA_START + tempDataLen++] = ch;    
            if (tempDataLen == pu16Length)    //数据存储完毕
            {
                state = FCS_STATE;
            }
            break;

        //数据存储结束，重新开始收集数据
        case FCS_STATE:    
            //最后一个字节：校验码
            if ((get_check_sum((unsigned char *) leokey_ble_queue_buf, pu16Length + PROTOCOL_HEAD) == ch))    
            {
                leokey_ble_queue_buf[DATA_START + tempDataLen] = ch;    //存储checksum
                tempDataLen = 0;
                state = SOP_INIT;

                my_memcpy((void *) leokey_ble_uart_rx_buf, (const char *) leokey_ble_queue_buf,
                          pu16Length + PROTOCOL_HEAD +1);    //若校验码正确，拷贝至内存
                
                rx_in = 1;    //有数据
                rx_length = pu16Length + PROTOCOL_HEAD +1; //数据长度
            }
            else    //检验码错误  
            {
                tempDataLen = 0;
                state = SOP_INIT;
                my_memset((void *) leokey_ble_queue_buf, 0, sizeof(leokey_ble_queue_buf));    //清除接收缓存
            }
            break;

        default:
            return 0;
    }
    return 1;
}


//============================================================================
//============================================================================


/*****************************************************************************
函数名称  : leokey_ble_uart_service
功能描述  : leokey_ble串口处理服务
输入参数 : 无
返回参数 : 无
使用说明 : 在MCU主函数while循环中调用该函数
*****************************************************************************/
void leokey_ble_uart_service(void)
{
    //#error "3、请在主循环函数中添加leokey_ble_uart_service()完成leokey_ble协议出具处理,并删除该行"
    if (rx_in)    //有数据
    {
        
        LeoKey_Printf("leokey_ble_uart_rx_buf: [%d]\r\n", rx_length);
        
        Hexdump_Debug((uint8_t *)leokey_ble_uart_rx_buf, rx_length, ' ');
        
        data_handle();
        
    }
}


//============================================================================
//============================================================================


/*****************************************************************************
函数名称 : leokey_ble_protocol_init
功能描述 : 协议串口初始化函数
输入参数 : 无
返回参数 : 无
使用说明 : 必须在MCU初始化代码中调用该函数
*****************************************************************************/
void leokey_ble_protocol_init(void)
{
    //#error "2、请在main函数中添加leokey_ble_protocol_init()完成leokey_ble协议初始化,并删除该行"
    my_memset((void *) leokey_ble_uart_rx_buf, 0, sizeof(leokey_ble_uart_rx_buf));
    rx_in = 0;
    rx_length = 0;

    
    my_memset((void *) timestamp, 0, sizeof(timestamp));
    
    
#ifdef SUPPORT_MCU_FIRM_UPDATE

    
#endif
    
    
}
